package com.zh.seckill.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.seckill.mapper.OrderMapper;
import com.zh.seckill.pojo.Order;
import com.zh.seckill.pojo.SeckillGoods;
import com.zh.seckill.pojo.SeckillOrder;
import com.zh.seckill.pojo.User;
import com.zh.seckill.service.OrderService;
import com.zh.seckill.service.SeckillGoodsService;
import com.zh.seckill.util.MD5Util;
import com.zh.seckill.util.UUIDUtil;
import com.zh.seckill.vo.GoodsVo;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Resource
    private SeckillGoodsService seckillGoodsService;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private SecKillOrderServiceImpl seckillOrderService;

    @Override
    @Transactional
    public Order seckill(User user, GoodsVo goodsVo) {
        SeckillGoods seckillGoods =
                seckillGoodsService.getOne(new QueryWrapper<SeckillGoods>().eq("id", goodsVo.getId()));
        //完成基本秒杀操作，这两条语句不具备原子性
        // seckillGoods.setStockCount(seckillGoods.getStockCount() - 1);
        // seckillGoodsService.updateById(seckillGoods);

        //利用MySQL的原子性来完成
        //MySQL的默认事务隔离级别是REPEATABLE-READ
        //执行update 语句的时候，如果存在行锁，那么就会阻塞，直到锁被释放。
        // 也就是读已提交，也就是读到的是最新数据，但是写操作是未提交的，也就是写操作是未提交的数据。
        //防止其他会话读取到未提交的数据，导致数据不一致。
        //  return null != result && result >= 1;为真
        boolean update = seckillGoodsService.update(new UpdateWrapper<SeckillGoods>()
                .setSql("stock_count=stock_count-1")
                .eq("goods_id", goodsVo.getId())
                .gt("stock_count", 0));

        if (!update) {
            return null;
        }

        //生成普通订单
        Order order = new Order();
        order.setUserId(user.getId());
        order.setGoodsId(goodsVo.getId());
        order.setDeliveryAddrId(0L);//设置一个初始值
        order.setGoodsName(goodsVo.getGoodsName());
        order.setGoodsCount(1);
        order.setGoodsPrice(seckillGoods.getSeckillPrice());
        order.setOrderChannel(1);//设置一个初始值
        order.setStatus(0);//设置一个初始值-未支付
        order.setCreateDate(new Date());//设置成now
        //保存order
        orderMapper.insert(order);

        //生成秒杀商品订单
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setGoodsId(goodsVo.getId());
        seckillOrder.setOrderId(order.getId());
        seckillOrder.setUserId(user.getId());
        //保存seckillOrder
        seckillOrderService.save(seckillOrder);

        //将生成秒杀订单存入到redis
        redisTemplate.opsForValue().set("order:" + user.getId() + ":" + goodsVo.getId(), seckillOrder);

        return order;
    }

    //方法: 生成秒杀路径/值(唯一)
    @Override
    public String createPath(User user, Long goodsId) {
        //生成秒杀路径/值
        String path = MD5Util.md5(UUIDUtil.uuid());
        //将随机生成的路径保存到Redis, 设置一个超时时间60s
        //key的设计: seckillPath:userId:goodsId
        redisTemplate.opsForValue().set("seckillPath:"
                + user.getId() + ":" + goodsId, path, 60, TimeUnit.SECONDS);
        return path;
    }

    //方法: 对秒杀路径进行校验
    @Override
    public boolean checkPath(User user, Long goodsId, String path) {
        if (user == null || goodsId < 0 || !StringUtils.hasText(path)) {
            return false;
        }

        //取出该用户秒杀该商品的路径
        String redisPath = (String) redisTemplate.opsForValue().get("seckillPath:" + user.getId() + ":" + goodsId);
        return path.equals(redisPath);
    }

   // 方法: 验证用户输入的验证码是否正确
    @Override
    public boolean checkCaptcha(User user, Long goodsId, String captcha) {
        if (user == null || goodsId < 0 || !StringUtils.hasText(captcha)) {
            return false;
        }

        //从Redis取出验证码
        String redisCaptcha = (String) redisTemplate.opsForValue().get("captcha:" + user.getId() + ":" + goodsId);

        return captcha.equals(redisCaptcha);
    }

}
